package org.apache.ibatis.common.type;

import org.apache.ibatis.common.io.Resources;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.util.*;

/**
 * @Name TypeAliasRegistry
 * @Description: 类型别名注册表
 * 描述信息：该类是一个类型别名注册表，维护类型的别名于类型的对应关系。
 * 通过该注册表，我们就可以在很多场合使用类型的别名来指代具体的类型。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-05-09 17:56:13
 **/
public class TypeAliasRegistry {
    private final Map<String, Class<?>> typeAliases = new HashMap<>();

    public TypeAliasRegistry() {
        registerAlias("byte", Byte.class);
        registerAlias("short", Short.class);
        registerAlias("int", Integer.class);
        registerAlias("integer", Integer.class);
        registerAlias("long", Long.class);
        registerAlias("float", Float.class);
        registerAlias("double", Double.class);
        registerAlias("boolean", Boolean.class);

        registerAlias("byte[]", Byte[].class);
        registerAlias("short[]", Short[].class);
        registerAlias("int[]", Integer[].class);
        registerAlias("integer[]", Integer[].class);
        registerAlias("long[]", Long[].class);
        registerAlias("float[]", Float[].class);
        registerAlias("double[]", Double[].class);
        registerAlias("boolean[]", Boolean[].class);

        registerAlias("_byte", byte.class);
        registerAlias("_short", short.class);
        registerAlias("_int", int.class);
        registerAlias("_integer", int.class);
        registerAlias("_long", long.class);
        registerAlias("_float", float.class);
        registerAlias("_double", double.class);
        registerAlias("_boolean", boolean.class);

        registerAlias("_byte[]", byte[].class);
        registerAlias("_short[]", short[].class);
        registerAlias("_int[]", int[].class);
        registerAlias("_integer[]", int[].class);
        registerAlias("_long[]", long[].class);
        registerAlias("_float[]", float[].class);
        registerAlias("_double[]", double[].class);
        registerAlias("_boolean[]", boolean[].class);

        registerAlias("string", String.class);

        registerAlias("date", Date.class);
        registerAlias("decimal", BigDecimal.class);
        registerAlias("bigdecimal", BigDecimal.class);
        registerAlias("biginteger", BigInteger.class);
        registerAlias("object", Object.class);

        registerAlias("date[]", Date[].class);
        registerAlias("decimal[]", BigDecimal[].class);
        registerAlias("bigdecimal[]", BigDecimal[].class);
        registerAlias("biginteger[]", BigInteger[].class);
        registerAlias("object[]", Object[].class);

        registerAlias("collection", Collection.class);
        registerAlias("iterator", Iterator.class);
        registerAlias("list", List.class);
        registerAlias("arraylist", ArrayList.class);
        registerAlias("map", Map.class);
        registerAlias("hashmap", HashMap.class);

        registerAlias("ResultSet", ResultSet.class);
    }

    public void registerAliases(String packageName) {
        registerAliases(packageName, Object.class);
    }

    public void registerAliases(String packageName, Class<?> superType) {
        // TODO 需要依赖 io 子包中的类，暂时用不到，后期补充。
    }

    public void registerAlias(Class<?> type) {
        String alias = type.getSimpleName();
        Alias aliasAnnotation = type.getAnnotation(Alias.class);
        if (aliasAnnotation != null) alias = aliasAnnotation.value();
        registerAlias(alias, type);
    }

    public void registerAlias(String alias, String value) {
        try {
            registerAlias(alias, Resources.classForName(value));
        } catch (ClassNotFoundException e) {
            String errorMsg = "无法注册类型别名 [" + alias + "] -> + value [" + value + "]，错误原因：" + e;
            throw new TypeException(errorMsg, e);
        }
    }

    public void registerAlias(String alias, Class<?> value) {
        if (alias == null) throw new TypeException("别名不能为 null。");
        String key = alias.toLowerCase(Locale.ENGLISH);
        if (typeAliases.containsKey(key) && typeAliases.get(key) != null && !typeAliases.get(key).equals(value)) {
            String errorMsg = "别名 [" + alias + "] 已经存在于注册表中，映射 value 为 [" + typeAliases.get(key).getName() + "]。";
            throw new TypeException(errorMsg);
        }
        typeAliases.put(key, value);
    }

    public Map<String, Class<?>> getTypeAliases() {
        return typeAliases;
    }

    public <T> Class<T> resolveAlias(String alias) {
        try {
            if (alias == null) return null;
            String key = alias.toLowerCase(Locale.ENGLISH);
            Class<T> value;
            if (typeAliases.containsKey(key)) value = (Class<T>) typeAliases.get(key);
            else value = (Class<T>) Resources.classForName(alias);
            return value;
        } catch (ClassNotFoundException e) {
            String errorMsg = "无法解析类型别名 [" + alias + "]，错误原因：" + e;
            throw new TypeException(errorMsg, e);
        }
    }
}

